package com.xiaoshuidi.cloud.framework.hangxin.core.client;

import cn.hutool.core.codec.Base64;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.util.json.JsonUtils;
import com.xiaoshuidi.cloud.framework.hangxin.core.dto.InvoicingItemDTO;
import com.xiaoshuidi.cloud.framework.hangxin.core.dto.InvoicingReqDTO;
import com.xiaoshuidi.cloud.framework.hangxin.core.dto.InvoicingRespDTO;
import com.xiaoshuidi.cloud.framework.hangxin.core.wsdl.EiexInvWebServiceImpl;
import com.xiaoshuidi.cloud.framework.hangxin.core.wsdl.IEIexnvWebService;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.ext.logging.LoggingOutInterceptor;
import org.apache.cxf.frontend.ClientProxy;
import org.springframework.util.StringUtils;

/**
 * 航信webservice请求客户端
 */
@Slf4j
public class HangxinWebserviceClient {
    private XmlMapper xmlMapper = new XmlMapper();
    private IEIexnvWebService ieIexnvWebService;

    public HangxinWebserviceClient() {
        ieIexnvWebService = new EiexInvWebServiceImpl().getEiexInvWebServiceImplPort();
        Client proxy = ClientProxy.getClient(ieIexnvWebService);
        proxy.getOutInterceptors().add(new LoggingOutInterceptor());
    }

    public InvoicingRespDTO call(InvoicingReqDTO reqDTO) {
        log.info("开票参数: {}", JsonUtils.toJsonString(reqDTO));
//        Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO);
        String body = buildRequestBody("FPKJ", reqDTO.getTaxpayerId(),
                reqDTO.getAuthorizationCode(), buildInvoiceRequest(reqDTO));
//        String resp = HttpUtil.post("https://csxtqd.nuocity.com/open/services/eiexInvWebService?wsdl", body);
        String resp = ieIexnvWebService.eiInterface(body);
        log.info("开票返回结果: {}", resp);
        return parseResponse(resp, InvoicingRespDTO.class);
    }

    /**
     * @param interfaceCode     接口编码
     * @param taxpayerId        纳税人识别号
     * @param authorizationCode 系统平台授权码
     * @param body
     * @return
     */
    private String buildRequestBody(String interfaceCode, String taxpayerId, String authorizationCode, String body) {
        log.info("开票原始请求参数: {}", body);
        body = Base64.encode(body);
        body = body.replaceAll("/", "_a").replaceAll("\\+", "_b")
                .replaceAll("=", "_c");
        return "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
                "<interface xmlns=\"\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
                "<globalInfo>\n" +
                " <version>1.0</version>\n" +
                " <interfaceCode>" + interfaceCode + "</interfaceCode>\n" +
                " <taxpayerId>" + taxpayerId + "</taxpayerId>\n" +
                " <authorizationCode>" + authorizationCode + "</authorizationCode>\n" +
                "</globalInfo>\n" +
                "<returnStateInfo>\n" +
                " <returnCode></returnCode>\n" +
                " <returnMessage></returnMessage>\n" +
                "</returnStateInfo>\n" +
                "<Data>\n" +
                " <dataDescription>\n" +
                " <zipCode>0</zipCode>\n" +
                " <encryptCode>0</encryptCode>\n" +
                " <codeType>0</codeType>\n" +
                " </dataDescription>\n" +
                " <content>" + body + "</content>\n</Data>\n</interface>";
    }

    private String buildInvoiceRequest(InvoicingReqDTO info) {
        StringBuilder sb = new StringBuilder("<REQUEST_COMMON_FPKJ class=\"REQUEST_COMMON_FPKJ\">\n" +
                " <COMMON_FPKJ_FPT class=\"COMMON_FPKJ_FPT\">\n" +
                "   <FPZL>" + ifnull(info.getFPZL()) + "</FPZL>\n" +
                "   <FPQQLSH>" + ifnull(info.getFPQQLSH()) + "</FPQQLSH>\n" +
                "   <DDH>" + ifnull(info.getDDH()) + "</DDH>\n" +
                "   <KPLX>" + ifnull(info.getKPLX()) + "</KPLX>\n" +
                "   <BMB_BBH>" + ifnull(info.getBMB_BBH()) + "</BMB_BBH>\n" +
                "   <XHQD>" + ifnull(info.getXHQD()) + "</XHQD>\n" +
                "   <XSF_NSRSBH>" + ifnull(info.getXSF_NSRSBH()) + "</XSF_NSRSBH>\n" +
                "   <XSF_MC>" + ifnull(info.getXSF_MC()) + "</XSF_MC>\n" +
                "   <XSF_DZDH>" + ifnull(info.getXSF_DZDH()) + "</XSF_DZDH>\n" +
                "   <XSF_YHZH>" + ifnull(info.getXSF_YHZH()) + "</XSF_YHZH>\n" +
                "   <GMF_NSRSBH>" + ifnull(info.getGMF_NSRSBH()) + "</GMF_NSRSBH>\n" +
                "   <GMF_MC>" + ifnull(info.getGMF_MC()) + "</GMF_MC>\n" +
                "   <GMF_DZDH>" + ifnull(info.getGMF_DZDH()) + "</GMF_DZDH>\n" +
                "   <GMF_YHZH>" + ifnull(info.getGMF_YHZH()) + "</GMF_YHZH>\n" +
                "   <GMF_SJ>" + ifnull(info.getGMF_SJ()) + "</GMF_SJ>\n" +
                "   <GMF_EMAIL>" + ifnull(info.getGMF_EMAIL()) + "</GMF_EMAIL>\n" +
                "   <KPR>" + ifnull(info.getKPR()) + "</KPR>\n" +
                "   <SKR>" + ifnull(info.getSKR()) + "</SKR>\n" +
                "   <FHR>" + ifnull(info.getFHR()) + "</FHR>\n" +
                "   <YFP_DM>" + ifnull(info.getYFP_DM()) + "</YFP_DM>\n" +
                "   <YFP_HM>" + ifnull(info.getYFP_HM()) + "</YFP_HM>\n" +
                "   <YFPZL_DM>" + ifnull(info.getYFPZL_DM()) + "</YFPZL_DM >\n" +
                "   <YKPRQ>" + ifnull(info.getYKPRQ()) + "</YKPRQ>\n" +
                "   <CHYY>" + ifnull(info.getCHYY()) + "</CHYY>\n" +
                "   <JSHJ>" + ifnull(info.getJSHJ()) + "</JSHJ>\n" +
                "   <HJJE>" + ifnull(info.getHJJE()) + "</HJJE>\n" +
                "   <HJSE>" + ifnull(info.getHJSE()) + "</HJSE>\n" +
                "   <SSLKJLY>" + ifnull(info.getSSLKJLY()) + "</SSLKJLY>\n" +
                "   <BZ>" + ifnull(info.getBZ()) + "</BZ>\n" +
                " </COMMON_FPKJ_FPT>\n");
        sb.append("<COMMON_FPKJ_XMXXS class=\"COMMON_FPKJ_XMXX\" size=\"").append(info.getItems().size()).append("\">\n");
        for (InvoicingItemDTO item : info.getItems()) {
            sb.append("<COMMON_FPKJ_XMXX>\n")
                    .append("<FPHXZ>").append(ifnull(item.getFPHXZ())).append("</FPHXZ>\n")
                    .append("<SPBM>").append(ifnull(item.getSPBM())).append("</SPBM>\n")
                    .append("<YHZCBS>").append(ifnull(item.getYHZCBS())).append("</YHZCBS>\n")
                    .append("<LSLBS>").append(ifnull(item.getLSLBS())).append("</LSLBS>\n")
                    .append("<ZZSTSGL>").append(ifnull(item.getZZSTSGL())).append("</ZZSTSGL>\n")
                    .append("<XMMC>").append(ifnull(item.getXMMC())).append("</XMMC>\n")
                    .append("<GGXH>").append(ifnull(item.getGGXH())).append("</GGXH>\n")
                    .append("<DW>").append(ifnull(item.getDW())).append("</DW>\n")
                    .append("<XMSL>").append(ifnull(item.getXMSL())).append("</XMSL>\n")
                    .append("<XMDJ>").append(ifnull(item.getXMDJ())).append("</XMDJ>\n")
                    .append("<XMJE>").append(ifnull(item.getXMJE())).append("</XMJE>\n")
                    .append("<SL>").append(ifnull(item.getSL())).append("</SL>\n")
                    .append("<SE>").append(ifnull(item.getSE())).append("</SE>\n")
                    .append("<KCE>").append(ifnull(item.getKCE())).append("</KCE>\n")
                    .append("</COMMON_FPKJ_XMXX>\n");
        }
        sb.append("</COMMON_FPKJ_XMXXS>\n</REQUEST_COMMON_FPKJ>");
        return sb.toString();
    }

    private String ifnull(String value) {
        return StringUtils.hasText(value) ? value : "";
    }

    public InvoicingRespDTO query(String taxPayerId, String authCode, String seqNo) {
        String body = buildRequestBody("FPCX", taxPayerId,
                authCode, "<REQUEST_COMMON_FPCX class=\"REQUEST_COMMON_FPCX\">\n" +
                        " <FPQQLSH>"+seqNo+"</FPQQLSH>\n" +
                        "</REQUEST_COMMON_FPCX>");
        String resp = ieIexnvWebService.eiInterface(body);
        return parseResponse(resp, InvoicingRespDTO.class);
    }

    private <T> T parseResponse(String resp, Class<T> clazz) {
        try {
            JsonNode node = xmlMapper.readTree(resp);
            JsonNode returnStateInfo = node.get("returnStateInfo");
            String returnCode = returnStateInfo.get("returnCode").asText();
            String returnMessage = returnStateInfo.get("returnMessage").asText();
            returnMessage = Base64.decodeStr(returnMessage);
            if ("0000".equals(returnCode)) {
                String content = node.get("Data").get("content").asText();
                content = content.replaceAll("_a", "/").replaceAll("_b", "+")
                        .replaceAll("_c", "=");
                content = Base64.decodeStr(content);
                return xmlMapper.readValue(content, clazz);
            } else {
                throw new ServiceException(500, returnCode + ":" + returnMessage);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}
